package pl.streamsoft.currencyApp.services;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import pl.streamsoft.currencyApp.model.Currency;

public class DuoCurrencyService implements ICurrencyService {

	private final SessionFactory sessionFactory;
	private final ICurrencyService webServis = new WebCurrencyService();
	private final ICurrencyService dbService = new DataBaseCurrencyService();

	public DuoCurrencyService() {
		sessionFactory = new Configuration().configure().buildSessionFactory();
	}

	private Session getSession() {
		return sessionFactory.openSession();
	}

	public boolean dataBaseContainsCurrencies(Date dateOfPublication) {

		Session session = getSession();

		try {

			session.beginTransaction();

			Query query = session
					.getNamedQuery("Currency.getCurrenciesByDateOfPublication");
			query.setMaxResults(1);
			query.setDate("dateOfPublication", dateOfPublication);

			return query.uniqueResult() != null;

		} finally {
			session.getTransaction().commit();
			session.close();
		}
	}

	@Override
	public Collection<Currency> getCurrencies(Date dateOfPublication) {

		if (dataBaseContainsCurrencies(dateOfPublication)) {
			return dbService.getCurrencies(dateOfPublication);
		}

		Collection<Currency> currencies = webServis
				.getCurrencies(dateOfPublication);
		if (!currencies.isEmpty()) {
			dbService.addCurrency(currencies);
		}
		return currencies;
	}

	@Override
	public Collection<Currency> getCurrencies(Date fromDate, Date toDate) {

		Session session = getSession();
		Set<Date> dateSet;

		try {

			session.beginTransaction();

			Query query = session
					.getNamedQuery("Currency.getExistingDatesFromTo");
			query.setDate("fromDate", fromDate);
			query.setDate("toDate", toDate);

			dateSet = new HashSet<Date>(query.list());

		} finally {
			session.getTransaction().commit();
			session.close();
		}

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(fromDate);

		while (calendar.getTime().before(toDate)) {
			if (!dateSet.contains(calendar.getTime())) {
				Collection<Currency> currencies = webServis
						.getCurrencies(calendar.getTime());
				if (!currencies.isEmpty()) {
					dbService.addCurrency(currencies);
				}
			}
			calendar.add(Calendar.DATE, 1);
		}

		session = getSession();

		try {

			session.beginTransaction();

			Query query = session
					.getNamedQuery("Currency.getCurrenciesByDateFromTo");
			query.setDate("fromDate", fromDate);
			query.setDate("toDate", toDate);

			return query.list();

		} finally {
			session.getTransaction().commit();
			session.close();
		}
	}

	@Override
	public Currency getCurrencyByCode(Date dateOfPublication, String codeName) {

		if (dataBaseContainsCurrencies(dateOfPublication)) {
			return dbService.getCurrencyByCode(dateOfPublication, codeName);
		}

		Collection<Currency> currencies = webServis
				.getCurrencies(dateOfPublication);

		if (!currencies.isEmpty()) {
			dbService.addCurrency(currencies);
			return dbService.getCurrencyByCode(dateOfPublication, codeName);
		}

		return null;
	}

	@Override
	public Currency getCurrencyByName(Date dateOfPublication, String name) {

		if (dataBaseContainsCurrencies(dateOfPublication)) {
			return dbService.getCurrencyByName(dateOfPublication, name);
		}

		Collection<Currency> currencies = webServis
				.getCurrencies(dateOfPublication);

		if (!currencies.isEmpty()) {
			dbService.addCurrency(currencies);
			return dbService.getCurrencyByName(dateOfPublication, name);
		}

		return null;
	}

	@Override
	public Collection<Currency> getCurrenciesByKeyWord(Date dateOfPublication,
			String keyWord) {

		if (dataBaseContainsCurrencies(dateOfPublication)) {
			return dbService.getCurrenciesByKeyWord(dateOfPublication, keyWord);
		}

		Collection<Currency> currencies = webServis
				.getCurrencies(dateOfPublication);

		if (!currencies.isEmpty()) {
			dbService.addCurrency(currencies);
			return dbService.getCurrenciesByKeyWord(dateOfPublication, keyWord);
		}

		return Collections.EMPTY_LIST;
	}

	@Override
	public Collection<Currency> getCurrenciesByValue(Date dateOfPublication,
			BigDecimal minValue) {

		if (dataBaseContainsCurrencies(dateOfPublication)) {
			return dbService.getCurrenciesByValue(dateOfPublication, minValue);
		}

		Collection<Currency> currencies = webServis
				.getCurrencies(dateOfPublication);

		if (!currencies.isEmpty()) {
			dbService.addCurrency(currencies);
			return dbService.getCurrenciesByValue(dateOfPublication, minValue);
		}

		return Collections.EMPTY_LIST;
	}

	@Override
	public Collection<Currency> getCurrenciesByValue(Date dateOfPublication,
			BigDecimal minValue, BigDecimal maxValue) {

		if (dataBaseContainsCurrencies(dateOfPublication)) {
			return dbService.getCurrenciesByValue(dateOfPublication, minValue,
					maxValue);
		}

		Collection<Currency> currencies = webServis
				.getCurrencies(dateOfPublication);

		if (!currencies.isEmpty()) {
			dbService.addCurrency(currencies);
			return dbService.getCurrenciesByValue(dateOfPublication, minValue,
					maxValue);
		}

		return Collections.EMPTY_LIST;
	}

	@Override
	public Collection<Currency> getLatestCurrencies() {
		Date todayDate = Calendar.getInstance().getTime();

		if (dataBaseContainsCurrencies(todayDate)) {
			return dbService.getCurrencies(todayDate);
		}

		Collection<Currency> lastCurrencies = webServis.getLatestCurrencies();

		if (!lastCurrencies.isEmpty()
				&& !dataBaseContainsCurrencies(lastCurrencies.iterator().next()
						.getDateOfPublication())) {
			dbService.addCurrency(lastCurrencies);
		}

		return lastCurrencies;
	}

	@Override
	public void addCurrency(Currency currency) {
		dbService.addCurrency(currency);
	}

	@Override
	public void addCurrency(Collection<Currency> currencies) {
		dbService.addCurrency(currencies);
	}

	@Override
	public void remove(Currency currency) {
		dbService.remove(currency);
	}

	@Override
	public void update(Currency currency) {
		dbService.update(currency);
	}

}
